/*                                    _
 *   ___ _ __ ___ _ __ ___   ___   __| |
 *  / __| '__/ __| '_ ` _ \ / _ \ / _` |
 *  \__ \ |  \__ \ | | | | | (_) | (_| |
 *  |___/_|  |___/_| |_| |_|\___/ \__,_|                         
 *
 *	 _                                           
 *	(_. _  _ | _   _ _  _  _  _   _  _  _|   | _ 
 *	| || )(_||(-  | (_|| )(_)(-  |||(_)(_||_||(- 
 *	                      _/                     
 *                    
 ******************************************
 ******************************************
 ******************************************
 * . _ _  _ | _  _ _  _  _ _|_ _ _|_. _  _ 
 * || | ||_)|(/_| | |(/_| | | (_| | |(_)| |
 *       |                                 
 *
 *		Valve finally removed the finale auto-spawning, but also 
 *		dramatically upped the minimum distance needed to Survivors
 *		in order to spawn, without any bugfree means to customize the setting.
 *		(there is a convar, but it causes really odd things to happen)
 *	 
 *		This module allows changing the minimum distance to a Survivor
 *		in order to spawn. It is achieved by a PreThinkPost-Hook
 *		that checks the current Ghost Spawn State, and if that is found
 *		"Too Close to Spawn", it checks the distance to the Survivors
 *		against the custom setting and overrides the Spawn State when needed.
 *
 */                 

#define MODULE_NAME "FinaleGhostSpawnRange"

/*
static const STATE_ROUNDHASNTSTARTED		= 2;
static const STATE_CANBESEEN				= 128;
*/

static const String:GHOST_STATE_PROP[]		= "m_ghostSpawnState";
static const STATE_SPAWNREADY				= 0;
static const STATE_TOOCLOSE					= 256;

static Handle:cvarEnabled					= INVALID_HANDLE;
static Handle:cvarRangeSetting				= INVALID_HANDLE;

static bool:rangeModEnabled					= true;
static Float:rangeSettingValue				= 150.0;

FinaleRangeMod_OnModuleLoaded()
{
	cvarEnabled = 		CreateConVar("srs_finaleghost_rangemod_enabled", 	"1", 		" Turn the Range Mod Module on or off ", 									SRS_CVAR_DEFAULT_FLAGS);
	cvarRangeSetting = 	CreateConVar("srs_finaleghost_rangemod_range", 		"150.0", 	" How close to the Survivors are Infected allowed to spawn during Finale ", SRS_CVAR_DEFAULT_FLAGS);
	
	HookConVarChange(cvarEnabled, 			_FR_ConvarsChanged);
	HookConVarChange(cvarRangeSetting, 		_FR_ConvarsChanged);
	HookConVarChange(GetGameModeHandle(), 	_FR_ConvarsChanged);
}

public _FR_ConvarsChanged(Handle:convar, const String:oldValue[], const String:newValue[])
{
	rangeModEnabled = (GetConVarBool(cvarEnabled) && IsAllowedGameMode());
	rangeSettingValue = GetConVarFloat(cvarRangeSetting);
}

public _FR_OnClientPostAdminCheck(client)
{
    SDKHook(client, SDKHook_PreThinkPost, _FR_ThinkHookCallback);
}

public _FR_ThinkHookCallback(client)
{
	if (!rangeModEnabled
	|| !RoundStatus_IsFinale()
	|| L4D2_GetClientTeam(client) != L4D2Team_Infected
	|| !IsPlayerAlive(client)
	|| !IsPlayerSpawnGhost(client)) return;

	if (GetEntProp(client, Prop_Send, GHOST_STATE_PROP) == STATE_TOOCLOSE)
	{
		if (GetDistanceToNearestSurvivor(client) >= rangeSettingValue)
		{
			SetEntProp(client, Prop_Send, GHOST_STATE_PROP, STATE_SPAWNREADY);
			Debug_PrintSpam("Overrode Player %N Ghost Spawn State for lower distance", client);
		}
	}
}

static Float:GetDistanceToNearestSurvivor(client)
{
	decl Float:infectedorigin[3], Float:survivororigin[3];
	GetClientAbsOrigin(client, infectedorigin);

	new Float:distance;
	decl Float:comparevalue;
	FOR_EACH_ALIVE_SURVIVOR_INDEXED(i)
	{
		GetClientAbsOrigin(i, survivororigin);

		comparevalue = GetVectorDistance(infectedorigin, survivororigin);
		
		if (distance > comparevalue || distance == 0.0)
		{
			distance = comparevalue;
		}
	}
	
	if (distance == 0.0) return 9999.9;
	else return distance;
}

#undef MODULE_NAME

